class NadeCureWProj extends ROBallisticProjectile;

#exec OBJ LOAD FILE=ProjectileSounds.uax

// camera shakes //
var() vector ShakeRotMag;           // how far to rot view
var() vector ShakeRotRate;          // how fast to rot view
var() float  ShakeRotTime;          // how much time to rot the instigator's view
var() vector ShakeOffsetMag;        // max view offset vertically
var() vector ShakeOffsetRate;       // how fast to offset view vertically
var() float  ShakeOffsetTime;       // how much time to offset view

var() vector RotMag;            // how far to rot view
var() vector RotRate;           // how fast to rot view
var() float  RotTime;           // how much time to rot the instigator's view
var() vector OffsetMag;         // max view offset vertically
var() vector OffsetRate;        // how fast to offset view vertically
var() float  OffsetTime;        // how much time to offset view

var RocketTrailW SmokeTrail;
var vector Dir;
var bool bRing,bHitWater,bWaterStart;

var()   sound               ExplosionSound;     // The sound of the rocket exploding

var () int HealBoostAmount;
var () int ShieldBoostAmount;

var     bool                bDud;               // This rocket is a dud, it hit too soon
var()   float               ArmDistSquared;     // Distance this rocket arms itself at
var     class<DamageType>	ImpactDamageType;   // Damagetype of this rocket hitting something, but not exploding
var     int                 ImpactDamage;       // How much damage to do if this rocket impacts something without exploding

// Physics
var() 		float 		StraightFlightTime;          // How long the projectile and flies straight
var 		float 		TotalFlightTime;             // How long the rocket has been in flight
var 		bool 		bOutOfPropellant;            // Projectile is out of propellant
// Physics debugging
var 		vector 		OuttaPropLocation;

var         bool        bHasExploded;

replication
{
	reliable if(Role == ROLE_Authority)
		bDud;
}

simulated function PostNetReceive()
{
}

function Timer()
{
	Destroy();
}

simulated function HitWall(vector HitNormal, actor Wall)
{
	Super(Projectile).HitWall(HitNormal,Wall);
}

simulated function Explode(vector HitLocation, vector HitNormal)
{
//	local Controller C;
//	local PlayerController  LocalPlayer;
//	if(KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill!=Class'SRVetFieldMedic')
//		return;
	bHasExploded = True;
	//Spawn(Class'KFMod.HealingFX',,, HitLocation + HitNormal*20, rotator(HitNormal));
	//Log("Explode 33554432");
	Spawn(Class'PerksSimHostOrg.VirusMistSmoke',,, HitLocation + HitNormal*20, rotator(HitNormal));
	BlowUp(HitLocation);
	Destroy();
}

simulated function PostBeginPlay()
{
	local rotator SmokeRotation;

	BCInverse = 1 / BallisticCoefficient;

	if ( Level.NetMode != NM_DedicatedServer)
	{
		SmokeTrail = Spawn(class'RocketTrailW',self);
		SmokeTrail.SetBase(self);
		SmokeRotation.Pitch = 32768;
		SmokeTrail.SetRelativeRotation(SmokeRotation);
		//Corona = Spawn(class'KFMod.KFLAWCorona',self);
	}

	OrigLoc = Location;

	if( !bDud )
	{
		Dir = vector(Rotation);
		Velocity = speed * Dir;
	}

	if (PhysicsVolume.bWaterVolume)
	{
		bHitWater = True;
		Velocity=0.6*Velocity;
	}
	Super(Projectile).PostBeginPlay();
}

function TakeDamage( int Damage, Pawn InstigatedBy, Vector Hitlocation, Vector Momentum, class<DamageType> damageType, optional int HitIndex)
{
	Explode(HitLocation, vect(0,0,0));
}

simulated function Destroyed()
{
	if ( SmokeTrail != None )
	{
		SmokeTrail.HandleOwnerDestroyed();
	}

	if( !bHasExploded && !bHidden && !bDud )
		Explode(Location,vect(0,0,1));

	Super.Destroyed();
}

/* HurtRadius()
Hurt locally authoritative actors within the radius.
*/
simulated function HurtRadius( float DamageAmount, float DamageRadius, class<DamageType> DamageType, float Momentum, vector HitLocation )
{
	local actor Victims;
	local float damageScale, dist;
	local vector dirs;
	local int NumKilled;
	local KFMonster KFMonsterVictim;
	local Pawn P;
	local KFPawn KFP;
	local array<Pawn> CheckedPawns;
	local int i;
	local bool bAlreadyChecked;
	local KFPlayerReplicationInfo PRI;
	local int MedicReward;
	local KFHumanPawn Healed;
	local float HealSum; // for modifying based on perks

	if ( bHurtEntry )
		return;

	bHurtEntry = true;

	if(KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill!=Class'SRVetFieldMedic')
		return;

	foreach CollidingActors (class 'Actor', Victims, DamageRadius, HitLocation)
	{
		// don't let blast damage affect fluid - VisibleCollisingActors doesn't really work for them - jag
		if( (Hurtwall != Victims) && (Victims.Role == ROLE_Authority) && 
			!Victims.IsA('FluidSurfaceInfo') && ExtendedZCollision(Victims)==None )
		{
			dirs = Victims.Location - HitLocation;
			dist = FMax(1,VSize(dirs));
			dirs = dirs/dist;
			damageScale = 1 - FMax(0,(dist - Victims.CollisionRadius)/DamageRadius);
			if ( Instigator == None || Instigator.Controller == None )
				Victims.SetDelayedDamageInstigatorController( InstigatorController );
			if ( Victims == LastTouched )
				LastTouched = None;

			P = Pawn(Victims);

			if( P != none )
			{
				for (i = 0; i < CheckedPawns.Length; i++)
				{
					if (CheckedPawns[i] == P)
					{
						bAlreadyChecked = true;
						break;
					}
				}

				if( bAlreadyChecked )
				{
					bAlreadyChecked = false;
					P = none;
					continue;
				}

				KFMonsterVictim = KFMonster(Victims);

				if( KFMonsterVictim != none && KFMonsterVictim.Health <= 0 )
				{
					KFMonsterVictim = none;
				}

				KFP = KFPawn(Victims);

				if( KFMonsterVictim != none )
				{
					damageScale *= KFMonsterVictim.GetExposureTo(HitLocation/*Location + 15 * -Normal(PhysicsVolume.Gravity)*/);
				}
				else if( KFP != none )
				{
					damageScale *= KFP.GetExposureTo(HitLocation/*Location + 15 * -Normal(PhysicsVolume.Gravity)*/);
				}

				CheckedPawns[CheckedPawns.Length] = P;

				if ( damageScale <= 0)
				{
					P = none;
					continue;
				}
				else
				{
					//Victims = P;
					P = none;
				}
			}
			if (KFHumanPawn(Victims) != none)
			{
				Healed = KFHumanPawn(Victims);
				if (Instigator != none && Healed != none && Healed.Health > 0 &&
					Healed.Health <  Healed.HealthMax)
				{
					MedicReward = HealBoostAmount;
					PRI = KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo);
					if ( PRI != none && PRI.ClientVeteranSkill != none )
					{
						MedicReward *= PRI.ClientVeteranSkill.Static.GetHealPotency(PRI);
					}

					MedicReward *= damageScale; /* Reduce healing strength for then distance from explotion center increases */
					HealSum = MedicReward;

					if ((Healed.Health + Healed.healthToGive + MedicReward) > Healed.HealthMax )
					{
						MedicReward = Healed.HealthMax - (Healed.Health + Healed.healthToGive);
						if ( MedicReward < 0 )
						{
							MedicReward = 0;
						}
					}

					//Healed.GiveHealth(HealSum, Healed.HealthMax);
					if (Pawn(Victims).Health < KFHumanPawn(Victims).HealthMax)
						Pawn(Victims).Health = Min(KFHumanPawn(Victims).HealthMax, Pawn(Victims).Health + HealSum * 0.5);

/*                  if (Healed.ShieldStrength >= 0)
					{
					if (Healed.ShieldStrength < 75)
						Healed.AddShieldStrength(ShieldBoostAmount * damageScale * PRI.ClientVeteranSkill.Static.GetHealPotency(PRI) );
					}
*/
					if ( PRI != None )
					{
						if ( MedicReward > 0 && KFSteamStatsAndAchievements(PRI.SteamStatsAndAchievements) != none )
						{
							KFSteamStatsAndAchievements(PRI.SteamStatsAndAchievements).AddDamageHealed(MedicReward/2, true);
							ServerStStats(KFSteamStatsAndAchievements(PRI.SteamStatsAndAchievements)).AddDamageHealedWithM56(MedicReward/2);
						}

						// Give the medic reward money as a percentage of how much of the person's health they healed
						MedicReward = int((FMin(float(MedicReward),Healed.HealthMax)/Healed.HealthMax) * 60); // Increased to 80 in Balance Round 6, reduced to 60 in Round 7
						PRI.Score += MedicReward;
						PRI.ThreeSecondScore += MedicReward;
						PRI.Team.Score += MedicReward;

						if ( KFHumanPawn(Instigator) != none )
						{
							KFHumanPawn(Instigator).AlphaAmount = 255;
						}

						if( MP7MW(Instigator.Weapon) != none )
						{
							MP7MW(Instigator.Weapon).ClientSuccessfulHeal(Healed.PlayerReplicationInfo.PlayerName);
						}
					}
				//Spawn(Class'PerksSimHostOrg.EXHealingFX',,, Victims.Location + dirs*20, rotator(dirs));
				}
			}
			else
			{
				Victims.TakeDamage(damageScale * DamageAmount,Instigator,
								Victims.Location - 0.5 * (Victims.CollisionHeight + Victims.CollisionRadius) * dirs,
								(damageScale * Momentum * dirs),DamageType);
				if (Vehicle(Victims) != None && Vehicle(Victims).Health > 0)
					Vehicle(Victims).DriverRadiusDamage(DamageAmount, DamageRadius, InstigatorController, DamageType, Momentum, HitLocation);

				if( Role == ROLE_Authority && KFMonsterVictim != none && KFMonsterVictim.Health <= 0 )
				{
					NumKilled++;
				}
			}
		}
	}
	//Log("m56 Stage 3");
	if ( (LastTouched != None) && (LastTouched != self) && (LastTouched.Role == ROLE_Authority) && !LastTouched.IsA('FluidSurfaceInfo') )
	{
		Victims = LastTouched;
		LastTouched = None;
		dirs = Victims.Location - HitLocation;
		dist = FMax(1,VSize(dirs));
		dirs = dirs/dist;
		damageScale = FMax(Victims.CollisionRadius/(Victims.CollisionRadius + Victims.CollisionHeight),1 - FMax(0,(dist - Victims.CollisionRadius)/DamageRadius));
		if (KFHumanPawn(Victims) != none)
		{
			Healed = KFHumanPawn(Victims);
			if (Instigator != none && Healed != none && Healed.Health > 0 && Healed.Health <  Healed.HealthMax)
			{
				MedicReward = HealBoostAmount;
				PRI = KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo);
				if ( PRI != none && PRI.ClientVeteranSkill != none )
				{
					MedicReward *= PRI.ClientVeteranSkill.Static.GetHealPotency(PRI);
				}
				MedicReward *= damageScale; /* Reduce healing strength for then distance from explotion center increases */
				HealSum = MedicReward;
				if ( (Healed.Health + Healed.healthToGive + MedicReward) > Healed.HealthMax )
				{
					MedicReward = Healed.HealthMax - (Healed.Health + Healed.healthToGive);
					if ( MedicReward < 0 )
					{
						MedicReward = 0;
					}
				}
				//Log("m56 Stage 4");
				//Healed.GiveHealth(HealSum, Healed.HealthMax);
				if (Pawn(Victims).Health < KFHumanPawn(Victims).HealthMax)
					Pawn(Victims).Health = Min(KFHumanPawn(Victims).HealthMax, Pawn(Victims).Health + HealSum * 0.5);
/*           if (Healed.ShieldStrength >= 0)
			{
			if (Healed.ShieldStrength < 75)
				Healed.AddShieldStrength(ShieldBoostAmount * damageScale * PRI.ClientVeteranSkill.Static.GetHealPotency(PRI) );
			}
*/
				//Log("m56 Stage 5");
				if ( PRI != None )
				{
					if ( MedicReward > 0 && KFSteamStatsAndAchievements(PRI.SteamStatsAndAchievements) != none )
					{
						KFSteamStatsAndAchievements(PRI.SteamStatsAndAchievements).AddDamageHealed(MedicReward/2, true);
						ServerStStats(KFSteamStatsAndAchievements(PRI.SteamStatsAndAchievements)).AddDamageHealedWithM56(MedicReward/2);
					}
					// Give the medic reward money as a percentage of how much of the person's health they healed
					MedicReward = int((FMin(float(MedicReward),Healed.HealthMax)/Healed.HealthMax) * 60); // Increased to 80 in Balance Round 6, reduced to 60 in Round 7
					PRI.Score += MedicReward;
					PRI.ThreeSecondScore += MedicReward;
					PRI.Team.Score += MedicReward;
					if ( KFHumanPawn(Instigator) != none )
					{
						KFHumanPawn(Instigator).AlphaAmount = 255;
					}
					if( MP7MW(Instigator.Weapon) != none )
					{
						MP7MW(Instigator.Weapon).ClientSuccessfulHeal(Healed.PlayerReplicationInfo.PlayerName);
					}
				}
			//Spawn(Class'PerksSimHostOrg.EXHealingFX',,, Victims.Location + dirs*20, rotator(dirs));
			}
		}
		else
		{
			//Log("Stage 6");
			if ( Instigator == None || Instigator.Controller == None )
				Victims.SetDelayedDamageInstigatorController(InstigatorController);
			Victims.TakeDamage(damageScale * DamageAmount,Instigator,
							Victims.Location - 0.5 * (Victims.CollisionHeight + Victims.CollisionRadius) * dirs,
							(damageScale * Momentum * dirs),DamageType);
			if (Vehicle(Victims) != None && Vehicle(Victims).Health > 0)
				Vehicle(Victims).DriverRadiusDamage(DamageAmount, DamageRadius, InstigatorController, DamageType, Momentum, HitLocation);
		}
	}

	if( Role == ROLE_Authority )
	{
		if( NumKilled >= 4 )
		{
			KFGameType(Level.Game).DramaticEvent(0.05);
		}
		else if( NumKilled >= 2 )
		{
			KFGameType(Level.Game).DramaticEvent(0.03);
		}
	}
	bHurtEntry = false;
}

simulated function ProcessTouch(Actor Other, Vector HitLocation)
{
	PlaySound(Sound'ProjectileSounds.PTRD_deflect04',,2.0);
	if ( Other == none || Other == Instigator || Other.Base == Instigator  )
		return;

	// Use the instigator's location if it exists. This fixes issues with
	// the original location of the projectile being really far away from
	// the real Origloc due to it taking a couple of milliseconds to
	// replicate the location to the client and the first replicated location has
	// already moved quite a bit.
	if( Instigator != none )
	{
		OrigLoc = Instigator.Location;
	}

	if( !bDud && ((VSizeSquared(Location - OrigLoc) < ArmDistSquared) || OrigLoc == vect(0,0,0)) )
	{
		if( Role == ROLE_Authority )
		{
			AmbientSound=none;
			//PlaySound(Sound'ProjectileSounds.PTRD_deflect04',,2.0);
			Other.TakeDamage( ImpactDamage, Instigator, HitLocation, Normal(Velocity), ImpactDamageType );
		}
		bDud = false;//true;
	}

	if( !bDud )
	{
		Explode(HitLocation,Normal(HitLocation-Other.Location));
	}
}

simulated function Tick( float DeltaTime )
{
	SetRotation(Rotator(Normal(Velocity)));

	if( !bOutOfPropellant )
	{
		if ( TotalFlightTime <= StraightFlightTime )
		{
			TotalFlightTime += DeltaTime;
		}
		else
		{
			OuttaPropLocation = Location;
			bOutOfPropellant = true;
		}
	}

	if(  bOutOfPropellant && Physics != PHYS_Falling )
	{
		//log(" Projectile flew "$(VSize(OrigLoc - OuttaPropLocation)/50.0)$" meters before running out of juice");
			SetPhysics(PHYS_Falling);
	}

}

simulated function Landed( vector HitNormal )
{
	SetPhysics(PHYS_None);

	if( !bDud )
	{
		Explode(Location,HitNormal);
	}
	else
	{
		Destroy();
	}
}

defaultproperties
{
     ShakeRotMag=(X=600.000000,Y=600.000000,Z=600.000000)
     ShakeRotRate=(X=12500.000000,Y=12500.000000,Z=12500.000000)
     ShakeRotTime=6.000000
     ShakeOffsetMag=(X=5.000000,Y=10.000000,Z=5.000000)
     ShakeOffsetRate=(X=300.000000,Y=300.000000,Z=300.000000)
     ShakeOffsetTime=3.500000
     RotMag=(X=700.000000,Y=700.000000,Z=700.000000)
     RotRate=(X=12500.000000,Y=12500.000000,Z=12500.000000)
     RotTime=6.000000
     OffsetMag=(X=5.000000,Y=10.000000,Z=7.000000)
     OffsetRate=(X=300.000000,Y=300.000000,Z=300.000000)
     OffsetTime=3.500000
     ExplosionSound=SoundGroup'KF_MP7Snd.Dart.MP7_DartImpact'
     HealBoostAmount=100
     ArmDistSquared=90000.000000
     ImpactDamageType=Class'PerksSimHostOrg.DamTypeAcid'
     ImpactDamage=400
     StraightFlightTime=0.250000
     AmbientVolumeScale=5.000000
     Speed=8000.000000
     MaxSpeed=8000.000000
     Damage=1050.000000
     DamageRadius=600.000000
     MomentumTransfer=75000.000000
     MyDamageType=Class'PerksSimHostOrg.DamTypeAcid'
     DrawType=DT_StaticMesh
     StaticMesh=StaticMesh'kf_generic_sm.Bullet_Shells.40mm_Warhead'
     bUpdateSimulatedPosition=True
     LifeSpan=10.000000
     bUnlit=False
     SoundVolume=255
     SoundRadius=250.000000
     TransientSoundVolume=2.000000
     TransientSoundRadius=500.000000
     bNetNotify=True
     bBlockHitPointTraces=False
     ForceRadius=300.000000
     ForceScale=10.000000
}
